package com.mcxx.formulcount.gonshi;

import java.util.*;
import java.util.regex.Pattern;

public class ExpressCalculator {

    public static void main(String[] args) {
        Hashtable<String, Object> varValues = new Hashtable<String, Object>();
        String str1 = "补差";
        System.out.println(str1.equals("补差"));
        varValues.put("年龄", 25);
        varValues.put("健康状况", "重病");
        varValues.put("重病病种", "民政部门认定的其他病种");
        varValues.put("人员分类救助类别", "失独家庭");
        varValues.put("标准类型", "城市标准");
        varValues.put("保障金计算方式", "补差");
        varValues.put("保障人口数", 2);
        varValues.put("家庭月总收入", 0);
        varValues.put("残疾人数", 0);
        varValues.put("残疾等级", "无");

        varValues.put("城市标准", 7200);
        varValues.put("城市一档收入标准", "100");

        String str = "如果((标准类型 等于 \"城市标准\") 并且  (人员分类救助类别 等于 \"失独家庭\" ))那么{分类救助金=315;}否则如果((标准类型 等于 \"农村标准\" 并且 保障金计算方式 等于 \"补差\")  并且  (人员分类救助类别 等于 \"失独家庭\" ))那么{分类救助金=180;}";

        FormulaConvert cvt=new FormulaConvert();
        ArrayList<String> arr= cvt.SplitWord("{"+str+"}");
        RefObject rnt=new RefObject(0);
        ArrayList<ISentence> sts = BlockServer.build(arr, 0,rnt);

        try {
        	Map<String,Object> rnts = BlockServer.runCode(sts, varValues);
            for(String k : rnts.keySet()){
                System.out.println(k+"="+rnts.get(k));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

	List<String> words;

    OperateSymbol[] opSymbols;

    String[] digits;

    Dictionary<String, Object> varValues;
	public ExpressCalculator(){
		opSymbols= new OperateSymbol[23];
		opSymbols[0]=new OperateSymbol("+",100);
		opSymbols[1]=new OperateSymbol("-", 100);
		opSymbols[2]=new OperateSymbol("*",200);
		opSymbols[3]=new OperateSymbol("/",200);
		opSymbols[4]=new OperateSymbol("%",200);
		opSymbols[4].setDigNum(1);
		opSymbols[5]=new OperateSymbol("(",1000);
		opSymbols[6]=new OperateSymbol(")",-1000);
		opSymbols[7]=new OperateSymbol("[如果]",900);
		opSymbols[7].setDigNum(3);
		opSymbols[8]=new LgOperateSymbol("[in]",900 );
		opSymbols[8].setDigNum(2);
		opSymbols[9]=new CmpOperateSymbol(">",0);
		opSymbols[10]=new CmpOperateSymbol("≥",0);
		opSymbols[11]=new CmpOperateSymbol("<",0);
		opSymbols[12]=new CmpOperateSymbol("≤",0);
		opSymbols[13]= new CmpOperateSymbol("=",0);
		opSymbols[14]=new LgOperateSymbol ("[and]",-50);
		opSymbols[15]=new LgOperateSymbol ("[or]",-50);
		opSymbols[16]=new LgOperateSymbol ("[not]",-40);
		opSymbols[16].setDigNum(1);
		opSymbols[17]=new OperateSymbol(",",-500);
		opSymbols[17].setDigNum(1);

		opSymbols[18]=new OperateSymbol("[round]",900);
		opSymbols[19]=new OperateSymbol("[roundUp]",900);
		opSymbols[20]=new OperateSymbol("[VComp]",900);
		opSymbols[20].setDigNum(3);
		opSymbols[21]=new StringOperateSymbol("[VInclude]",900);
		opSymbols[22]= new CmpOperateSymbol("≠",0);


		this.digits = "0,1,2,3,4,5,6,7,8,9,.".split(",");


	}
	public ExpressCalculator(String expression, Dictionary<String,Object> VarPropObject){
		this();
		words = splitWord(expression);
		varValues=VarPropObject;
	}

	public List<String> splitWord(String exp){
		String tmp = exp;
        String[] ConvertToDH = new String[] { "[则]", "[否]" };
        for( int i=0;i<ConvertToDH.length;i++){
        	String s=ConvertToDH[i];
        	tmp = tmp.replace(s, ",");
        }
        for(int i=0;i<opSymbols.length;i++){
        	String symb=opSymbols[i].getSymbol();
        	tmp=tmp.replace(symb ,"▲S_L_P_T▲" + symb + "▲S_L_P_T▲");
        }
        String[] arr = tmp.split("▲S_L_P_T▲");
        List<String> rnt=new ArrayList<String>();
        for(int i=0;i<arr.length;i++){
        	if(!arr[i].trim().equals("")) {
                rnt.add(arr[i].trim());
            }
        }
        return rnt;
	}

	private OperateSymbol strToSymbol(String str)
    {
		for(int i=0;i<this.opSymbols.length;i++){
			OperateSymbol smb=opSymbols[i];
			if (smb.getSymbol().equals(str)) {
                return smb;
            }
		}
        return null;
    }
	private boolean isSymbol(String str)
    {
        boolean Find = false; ;
        for(int i=0;i<this.opSymbols.length;i++){
        	String smb=opSymbols[i].getSymbol();
        	if (smb.equals(str)){
        		Find = true;
        		break;
        	}
        }
        return Find;
    }

	private Object getVarValue(String vars) throws Exception
    {
        double num = 0;

        if (!this.isDoubleOrFloat(vars))
        {

            if (vars.startsWith("'") && vars.endsWith("'")) {
                return vars.replace("'", "");
            }

            if (varValues.get(vars)==null) {
                throw new Exception("公式错误,变量:"+vars+" 不存在");
            }
            return  varValues.get(vars);
        }
        else {
            num=Double.parseDouble(vars);
        }
        return num;
    }

	public  boolean isDoubleOrFloat(String str) {
        Pattern pattern = Pattern.compile("^[-\\+]?[.\\d]*$");
        return pattern.matcher(str).matches();
    }

	private void procSymbol(String cur, Stack<OperateSymbol> Symbols, Stack<Object> Nums) throws Exception
    {
        OperateSymbol curSmb = strToSymbol(cur);
        if (Symbols.empty())
        {
            Symbols.push(curSmb);
            return;
        }
        do
        {
            OperateSymbol topSmb = Symbols.pop();
            if (curSmb.getPriority() <= topSmb.getPriority())
            {
                if (curSmb.getSymbol().equals(")") && topSmb.getSymbol().equals("(")) {
                    return;
                }
                if (topSmb.getSymbol().equals("("))
                {
                    Symbols.push(topSmb);
                    Symbols.push(curSmb);
                    return;
                }
                if (topSmb.getDigNum() == 1)
                {
                    Object n = Nums.pop();
                    Nums.push(topSmb.Caluc(n));
                }
                if (topSmb.getDigNum() == 2)
                {
                    Object b = Nums.pop();
                    Object a = Nums.pop();
                    Nums.push(topSmb.Caluc(a, b));
                }
                if (topSmb.digNum == 3)
                {
                    Object c = Nums.pop();
                    Object b = Nums.pop();
                    Object a = Nums.pop();
                    Nums.push(topSmb.Caluc(a, b, c));
                }
            }
            else
            {
                Symbols.push(topSmb);
                Symbols.push(curSmb);
                return;
            }
        } while (!Symbols.empty());
        Symbols.push(curSmb);
    }

	public Object getValue() throws Exception
    {
        Stack<OperateSymbol> Symbols = new Stack<OperateSymbol>();
        Stack<Object> Nums = new Stack<Object>();
        int pw = 0;
        String cur = words.get(pw).trim();

        while (pw < words.size())
        {
            cur = words.get(pw).trim();
            if (isSymbol(cur))
            {
                procSymbol(cur, Symbols, Nums);
            }
            else {
                Nums.push(getVarValue(cur));
            }
            pw++;
        }
        while (!Symbols.empty())
        {

            if (pw >= words.size())
            {
                OperateSymbol topSmb = Symbols.pop();
                if (topSmb.getDigNum() == 1)
                {
                    Object n = Nums.pop();
                    Nums.push(topSmb.Caluc(n));
                }
                if (topSmb.getDigNum() == 2)
                {
                    Object b = Nums.pop();
                    Object a = Nums.pop();
                    Nums.push(topSmb.Caluc(a, b));
                }
                if (topSmb.getDigNum() == 3)
                {
                    Object c = Nums.pop();
                    Object b = Nums.pop();
                    Object a = Nums.pop();
                    Nums.push(topSmb.Caluc(a, b, c));
                }
                continue;
            }
        }
        return Nums.peek();
    }
}
